from Common import *
import DictParamChecker
import DB
import time

class Budget:
    def __init__(self, logger, global_data):
        self.db = DB.DB(logger)
        self.logger = logger
        self.global_data = global_data

    def __specialValueTransfer(self, args):
        '''转换从数据库返回的数据中的某些值
        没有返回值'''
        args['mon1'] = fenIntToYuanStr(args['mon1'])
        args['mon2'] = fenIntToYuanStr(args['mon2'])
        args['mon3'] = fenIntToYuanStr(args['mon3'])
        args['mon4'] = fenIntToYuanStr(args['mon4'])
        args['mon5'] = fenIntToYuanStr(args['mon5'])
        args['mon6'] = fenIntToYuanStr(args['mon6'])
        args['mon7'] = fenIntToYuanStr(args['mon7'])
        args['mon8'] = fenIntToYuanStr(args['mon8'])
        args['mon9'] = fenIntToYuanStr(args['mon9'])
        args['mon10'] = fenIntToYuanStr(args['mon10'])
        args['mon11'] = fenIntToYuanStr(args['mon11'])
        args['mon12'] = fenIntToYuanStr(args['mon12'])
        args['all_year'] = fenIntToYuanStr(args['all_year'])

    def __calculateBudgetStatus(self, plan, left):
        '''计算预算的当前状态
        返回值：'plenty', 'normal', 'low', 'exceed'之一，对应预算剩余>80%, >20%, >0%, <0%
        plan: 预算值
        left: 预算剩余值'''
        if left < 0:
            return 'exceed'
        if left == 0:
            if plan == 0:
                return 'normal'
            return 'low'
        rate = left / plan
        if rate > 0.8:
            return 'plenty'
        if rate > 0.2:
            return 'normal'
        return 'low'

    def getCurrentPlanAndUsage(self, args):
        '''獲取當前預算的使用狀況，返回格式為
        {cat1s:[{}...], all_cat1s:{}}
        {}中的內容包括：month_left,cur_month_usage,month_plan,year_left,cur_year_usage,year_plan}
        在时间范围内，涉及到已经删除的分类也会展示出来'''
        current_time_ms = int(time.time())
        ret = timestampToCurrentDayMonthYearTimestamp(current_time_ms)
        cur_month_ms = ret['month']
        cur_year_ms = ret['year']
        cur_month = time.localtime(current_time_ms).tm_mon

        # 獲取本月、本年的預算
        ret = self.db.call('getBudgetPlan', {})
        if ret['errno'] != Error.SUCCESS:
            return ret
        budget_plan = ret['data']

        # 计算当前总预算，并写入budget_plan
        all_month_names = ['', 'mon1', 'mon2', 'mon3', 'mon4', 'mon5', 'mon6', 'mon7', 'mon8', 'mon9', 'mon10', 'mon11', 'mon12']
        month_names = all_month_names[1: cur_month + 1]
        for i in range(0, len(budget_plan['cat1_plan'])):
            plan = budget_plan['cat1_plan'][i]
            cur_total_budget = 0
            for month_name in month_names:
                cur_total_budget += plan[month_name]
            budget_plan['cat1_plan'][i]['cur_total'] = cur_total_budget
        cur_total_budget = 0
        for month_name in month_names:
            cur_total_budget += budget_plan['all_cat1s_plan'][month_name]
        budget_plan['all_cat1s_plan']['cur_total'] = cur_total_budget

        # 獲取本月各个分类的支出总计，并转换成cat1_id:amount的格式
        args = {'begin_time' : cur_month_ms, 'end_time' : current_time_ms}
        ret = self.db.call('getPaymentCostGroupedByCat1InTimeRange', args)
        if ret['errno'] != Error.SUCCESS:
            return ret
        ret = ret['data']
        month_usage = {}
        total = 0
        for info in ret:
            total += info['amount']
            month_usage[info['cat1_id']] = info['amount']
        month_usage[1] = total

        # 獲取本年各个分类的支出总计，并转换成cat1_id:amount的格式
        args['begin_time'] = cur_year_ms
        ret = self.db.call('getPaymentCostGroupedByCat1InTimeRange', args)
        if ret['errno'] != Error.SUCCESS:
            return ret
        ret = ret['data']
        year_usage = {}
        total = 0
        for info in ret:
            total += info['amount']
            year_usage[info['cat1_id']] = info['amount']
        year_usage[1] = total
        
        # 把月、年支出中未出现的一级分类的支出设为0
        # 支出一级分类信息在budget_plan中已经包含
        for plan in budget_plan['cat1_plan']:
            cat1_id = plan['cat1_id']
            if cat1_id not in month_usage:
                month_usage[cat1_id] = 0
            if cat1_id not in year_usage:
                year_usage[cat1_id] = 0

        # 把所有信息拼在一起
        # 包含：分类信息、本月预算、本月剩余、状态、当前总预算、当前总剩余、状态、本年预算、本年剩余、状态
        cat1_info = []
        month_column_name = all_month_names[cur_month]
        month_left = 0
        year_left = 0
        for plan in budget_plan['cat1_plan']:
            cat1_id = plan['cat1_id']
            month_left = plan[month_column_name] - month_usage[cat1_id]
            cur_total_left = plan['cur_total'] - year_usage[cat1_id]
            year_left = plan['all_year'] - year_usage[cat1_id]
            cat1_info.append({\
                'cat1_id':cat1_id,\
                'cat1_nameme':plan['cat1_nameme'],\
                'month_plan':fenIntToYuanStr(plan[month_column_name]),\
                'month_left':fenIntToYuanStr(month_left),\
                'month_status':self.__calculateBudgetStatus(plan[month_column_name], month_left),\
                'cur_total_plan':fenIntToYuanStr(plan['cur_total']),\
                'cur_total_left':fenIntToYuanStr(cur_total_left),\
                'cur_total_status':self.__calculateBudgetStatus(plan['cur_total'], cur_total_left),\
                'year_plan':fenIntToYuanStr(plan['all_year']),\
                'year_left':fenIntToYuanStr(year_left),\
                'year_status':self.__calculateBudgetStatus(plan['all_year'], year_left)})
        plan = budget_plan['all_cat1s_plan']
        cat1_id = plan['cat1_id']
        month_left = plan[month_column_name] - month_usage[cat1_id]
        cur_total_left = plan['cur_total'] - year_usage[cat1_id]
        year_left = plan['all_year'] - year_usage[cat1_id]
        all_cat1s_info = {\
            'cat1_id':cat1_id,\
            'cat1_nameme':plan['cat1_nameme'],\
            'month_plan':fenIntToYuanStr(plan[month_column_name]),\
            'month_left':fenIntToYuanStr(month_left),\
            'month_status':self.__calculateBudgetStatus(plan[month_column_name], month_left),\
            'cur_total_plan':fenIntToYuanStr(plan['cur_total']),\
            'cur_total_left':fenIntToYuanStr(cur_total_left),\
            'cur_total_status':self.__calculateBudgetStatus(plan['cur_total'], cur_total_left),\
            'year_plan':fenIntToYuanStr(plan['all_year']),\
            'year_left':fenIntToYuanStr(year_left),\
            'year_status':self.__calculateBudgetStatus(plan['all_year'], year_left)}
        return makeReturn(Error.SUCCESS, {'cat1_info':cat1_info, 'all_cat1s_info':all_cat1s_info})

    def getPlan(self, args):
        '''获取预算计划'''
        ret = self.db.call('getBudgetPlan', {})
        if ret['errno'] != Error.SUCCESS:
            return ret
        for i in range(0, len(ret['data']['cat1_plan'])):
            self.__specialValueTransfer(ret['data']['cat1_plan'][i])
        self.__specialValueTransfer(ret['data']['all_cat1s_plan'])
        return ret
        
    def setCat1(self, args):
        '''設置一個一級支出的預算'''
        checker = DictParamChecker.DictParamChecker()
        checker.addParam('cat1_id', 'int', True)
        checker.addParam('mon1', 'int', True)
        checker.addParam('mon2', 'int', True)
        checker.addParam('mon3', 'int', True)
        checker.addParam('mon4', 'int', True)
        checker.addParam('mon5', 'int', True)
        checker.addParam('mon6', 'int', True)
        checker.addParam('mon7', 'int', True)
        checker.addParam('mon8', 'int', True)
        checker.addParam('mon9', 'int', True)
        checker.addParam('mon10', 'int', True)
        checker.addParam('mon11', 'int', True)
        checker.addParam('mon12', 'int', True)
        checker.addParam('all_year', 'int', True)
        checker.addParam('descriptiontion', 'str', True)
        args = checker.check(args)
        if type(args) == str:
            return makeReturn(Error.ILLEGAL_ARGS, args)
        if args['cat1_id'] == 1:
            return makeReturn(Error.ILLEGAL_ARGS, 'illegal cat1_id')
        # 元轉換成分
        for mon in range(1, 13):
            key = 'mon' + str(mon)
            args[key] = yuanStrToFenInt(args[key])
        args['all_year'] = yuanStrToFenInt(args['all_year'])
        # 年預算必須大於等於個個月預算總合
        min_all_year = args['mon1'] + args['mon2'] + args['mon3'] + args['mon4'] + args['mon5'] + args['mon6'] +\
            args['mon7'] + args['mon8'] + args['mon9'] + args['mon10'] + args['mon11'] + args['mon12']
        if args['all_year'] < min_all_year:
            return makeReturn(Error.VALUE_ERROR, 'all_year is too small')
        return self.db.call('updateBudget', args)
